package org.budo.support.application.registry.redis;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.budo.support.application.registry.AbstractBudoApplicationRegistry;
import org.budo.support.application.registry.BudoApplication;
import org.budo.support.application.registry.BudoApplicationRegistry;
import org.budo.support.fastjson.Fastjson;
import org.budo.support.jedis.util.JedisUtil;
import org.budo.support.spring.util.SpringUtil;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * @author lmw
 */
@Slf4j
@Getter
@Setter
public class BudoRedisApplicationRegistry extends AbstractBudoApplicationRegistry {
    private static final String KEY_PREFIX = "budo:app:registry:";

    private JedisPool jedisPool;

    @Override
    public void register(BudoApplication application) {
        String key = KEY_PREFIX + application.getName() + ":" + application.getIp() + ":" + application.getPort();

        String json = Fastjson.toJSONString(application);

        Jedis jedis = this.jedisPool().getResource();
        jedis.setex(key, EXPIRE, json); // 过期时间
        jedis.close();

        log.debug("#52 register, this={}, key={}, val={}, EXPIRE={}, application={}", this, key, json, EXPIRE, application);
    }

    @Override
    public void unregister(BudoApplication application) {
        String key = KEY_PREFIX + application.getName() + ":" + application.getIp() + ":" + application.getPort();
        Jedis jedis = this.jedisPool().getResource();
        jedis.del(key);
        jedis.close();

        log.debug("#64 unregister, this={}, key={}, application={}", this, key, application);
    }

    @Override
    public List<BudoApplication> lookup(String applicationName) {
        String pattern = BudoApplicationRegistry.APPLICATION_NAME_ANY.equals(applicationName) //
                ? KEY_PREFIX + "*" //
                : KEY_PREFIX + applicationName + "*";

        Jedis jedis = this.jedisPool().getResource();
        Set<String> keys = jedis.keys(pattern);

        List<BudoApplication> list = new ArrayList<BudoApplication>();
        for (String key : keys) {
            String val = jedis.get(key);
            BudoApplication application = Fastjson.parseObject(val, BudoApplication.class);

            list.add(application);
        }

        jedis.close();
        return list;
    }

    /**
     * 这里加个 Redis 锁 减少 Nginx 上的请求次数
     */
    @Override
    protected void pushNginxUpstream() {
        String key = "budo:ApplicationRegistry:pushNginxUpstream:Lock"; // 锁
        int expireIn = 5; // 锁过期时间
        JedisUtil.tryLock(this.jedisPool(), key, this::compare_and_push_nginx_upstream, expireIn);
    }

    private JedisPool jedisPool() {
        if (null != this.getJedisPool()) {
            return this.getJedisPool();
        }

        JedisPool jedisPool = SpringUtil.getBeanCached(JedisPool.class);
        if (null != jedisPool) {
            return jedisPool;
        }

        throw new IllegalStateException("#47 this.jedisPool is null, this=" + this);
    }

    @Override
    public String toString() {
        return super.toString() + ", jedisPool=" + this.getJedisPool();
    }
}